package com.roin.tools.controller;

import com.roin.tools.App;
import com.roin.tools.service.DuplicateFileService;
import com.roin.tools.utils.DialogUtil;
import com.roin.tools.utils.StringUtils;
import com.roin.tools.views.OrderNumberCell;
import com.roin.tools.vo.DuplicateFile;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.util.Callback;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;


/**
 * 查找重复文件控制器
 * @author Roin
 */
public class DuplicateFileController extends AbstractController {

    private final static String DOT = ".";
    private final static String COMPARE_TYPE_MD5 = "MD5";

    private boolean isMd5 = true;

    private DuplicateFileService duplicateFileService;

    private List<String> audioTypeList = new ArrayList<String>(Arrays.asList(".mp3",".wav",".flac",".wma",".ogg",".aac",".ape"));
    private List<String> videoTypeList = new ArrayList<String>(Arrays.asList(".avi",".wmv",".mpg",".mpeg",".mov",".rm",".ram",".swf",".flv",".mp4",".3GP",".mkv",".rmvb",".m4v",".ogg"));
    private List<String> officeTypeList = new ArrayList<String>(Arrays.asList(".doc",".docx",".xls",".xlsx",".ppt",".pptx"));
    private List<String> compressedTypeList = new ArrayList<String>(Arrays.asList(".rar",".zip",".gz",".z",".7z"));;
    private List<String> imageTypeList = new ArrayList<String>(Arrays.asList("bmp",".dib",".emf",".gif",".icb",".ico",".jpg",".jpeg",".pbm",".pcd",".pcx",".pgm",".png",".ppm",".psd",".psp",".rle",".sgi",".tga",".tif"));;

    @FXML
    private TextField targetDir;
    @FXML
    private ToggleGroup compareType;
    @FXML
    private TextField excludeTexts;
    @FXML
    private TextField excludeDirs;
    @FXML
    private TextField fileTypes;
    @FXML
    private Slider fileNameSimilarity;
    @FXML
    private CheckBox audioTypes;
    @FXML
    private CheckBox videoTypes;
    @FXML
    private CheckBox officeTypes;
    @FXML
    private CheckBox compressedTypes;
    @FXML
    private CheckBox imageTypes;
    @FXML
    private TableView<DuplicateFile> resultTableView;
    @FXML
    private TableColumn indexColumn;
    @FXML
    private TableColumn<DuplicateFile,List<File>> fileColumn;
    @FXML
    private TableColumn handlerColumn;


    @FXML
    public void initialize() {
        super.init();
        //文件对比方式切换事件处理
        compareType.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            @Override
            public void changed(ObservableValue<? extends Toggle> observableValue, Toggle toggle, Toggle newToggle) {
                String userData = newToggle.getUserData().toString();
                isMd5 = (COMPARE_TYPE_MD5.equals(userData));
                //如果使用MD5方式，则不需要【文件名排除文字】和【文件名相似度】参数
                excludeTexts.setDisable(isMd5);
                fileNameSimilarity.setDisable(isMd5);
            }
        });
        duplicateFileService = new DuplicateFileService();
    }


    /**
     * 选择目标目录
     */
    @FXML
    private void selectDir() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择目录");
        String preDir = targetDir.getText();
        if (preDir != null && preDir != "") {
            File perFile = new File(preDir);
            if(perFile.exists()){
                directoryChooser.setInitialDirectory(perFile);
            }
        }
        File file = directoryChooser.showDialog(App.getStage());
        //选择的文件夹路径
        if (file != null) {
            String path = file.getPath();
            targetDir.setText(path);
        }
    }

    /**
     * 开始比较
     */
    @FXML
    private void startCompare() {
        resultTableView.setItems(FXCollections.emptyObservableList());
        String targetDirStr = targetDir.getText();
        String excludeDirsStr = excludeDirs.getText();
        String fileTypesStr = fileTypes.getText();
        File targetDir_ = new File(targetDirStr);

        if (!targetDir_.exists()) {
            DialogUtil.alert("请选择文件目录");
            return;
        }
        Set<String> fileTypeLimitList = new HashSet<>(2);
        if (StringUtils.isNotEmpty(fileTypesStr)) {
            String[] fileTypeLimitArray = fileTypesStr.split(",");
            for (String s : fileTypeLimitArray) {
                fileTypeLimitList.add(DOT + s);
            }
        }
        if(audioTypes.isSelected()){
            fileTypeLimitList.addAll(audioTypeList);
        }
        if(videoTypes.isSelected()){
            fileTypeLimitList.addAll(videoTypeList);
        }
        if(imageTypes.isSelected()){
            fileTypeLimitList.addAll(imageTypeList);
        }
        if(compressedTypes.isSelected()){
            fileTypeLimitList.addAll(compressedTypeList);
        }
        if(officeTypes.isSelected()){
            fileTypeLimitList.addAll(officeTypeList);
        }

        Set<String> excludeDirs = new HashSet<>(2);
        if (StringUtils.isNotEmpty(excludeDirsStr)) {
            String[] excludeDirsArray = excludeDirsStr.split(",");
            for (String s : excludeDirsArray) {
                excludeDirs.add(s);
            }
        }
        try {
            List<List<File>> resultList;
            if (isMd5) {
                resultList = duplicateFileService.findDuplicateFileByMD5(targetDir_, fileTypeLimitList, excludeDirs);
            } else {
                String excludeTextsStr = excludeTexts.getText();
                Double similarityValue = Double.valueOf(fileNameSimilarity.getValue());
                Set<String> excludeTexts = new HashSet<>(2);
                if (StringUtils.isNotEmpty(excludeTextsStr)) {
                    String[] excludeTextsArray = excludeTextsStr.split(",");
                    for (String s : excludeTextsArray) {
                        excludeTexts.add(s);
                    }
                }
                resultList = duplicateFileService.findDuplicateFileByName(targetDir_, fileTypeLimitList, excludeDirs,similarityValue.intValue(),excludeTexts);
            }
            System.out.println("共找到了"+resultList.size()+"组重复文件");
            if(resultList.isEmpty()){
                DialogUtil.alert("没有找到重复文件");
                return;
            }
            ObservableList<DuplicateFile> list =FXCollections.observableArrayList();
            for (List<File> files : resultList) {
                list.add(new DuplicateFile(null, files));
            }
            rendererResultView(list);

        } catch (IOException e) {
            e.printStackTrace();
            DialogUtil.alertException(e);
        }
    }

    private void rendererResultView(ObservableList<DuplicateFile> data){
        //相当于java中的ArrayList
        resultTableView.setItems(data);
        indexColumn.setCellFactory(new OrderNumberCell<>());
        fileColumn.setCellValueFactory(new PropertyValueFactory<DuplicateFile,  List<File>>("files"));
        fileColumn.setCellFactory(new Callback<>() {
            @Override
            public TableCell<DuplicateFile, List<File>> call(TableColumn<DuplicateFile, List<File>> duplicateFileListTableColumn) {
                return new TableCell<>() {
                    @Override
                    protected void updateItem(List<File> files, boolean isEmpty) {
                        super.updateItem(files, isEmpty);
                        if (!isEmpty) {
                            VBox vBox = new VBox();
                            vBox.setAlignment(Pos.CENTER_LEFT);
                            vBox.setSpacing(12);
                            for (File f : files) {
                                Label label = new Label(f.getAbsolutePath());
                                label.setUserData(f);
                                vBox.getChildren().add(label);
                            }
                            this.setGraphic(vBox);
                        }
                    }
                };
            }
        });
        handlerColumn.setCellValueFactory(new PropertyValueFactory<DuplicateFile,  List<File>>("files"));
        handlerColumn.setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn tableColumn) {
                return new TableCell<ObservableList<List<File>>,List<File>>(){
                    @Override
                    protected void updateItem(List<File> data, boolean isEmpty) {
                        super.updateItem(data, isEmpty);
                        if (!isEmpty){
                            VBox vBox = new VBox();
                            vBox.setSpacing(5);
                            for (File f : data) {
                                HBox hBox = new HBox();
                                hBox.setSpacing(5);
                                hBox.setUserData(f);
                                hBox.setAlignment(Pos.CENTER);
                                Button delBtn = new Button("删除");
                                delBtn.setOnAction(delButtonHandler);
                                Button moveBtn = new Button("移动");
                                moveBtn.setOnAction(moveButtonHandler);
                                Button copyBtn = new Button("复制");
                                copyBtn.setOnAction(copyButtonHandler);
                                hBox.getChildren().addAll(delBtn,moveBtn,copyBtn);
                                vBox.getChildren().add(hBox);
                            }
                            this.setGraphic(vBox);
                        }
                    }
                };
            }
        });

    }

    /**
     * 删除文件操作处理器
     */
    private EventHandler delButtonHandler = event -> {
        Button button = (Button) event.getSource();
        Parent parent = button.getParent();
        File file = (File) parent.getUserData();
        System.gc();
        if(file.exists() && file.delete()){
            parent.setDisable(true);

        }
    };

    /**
     * 移动文件操作处理器
     */
    private EventHandler moveButtonHandler = event -> {
        Button button = (Button) event.getSource();
        Parent parent = button.getParent();
        File file = (File) parent.getUserData();
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择目录");
        File dir = directoryChooser.showDialog(App.getStage());
        //选择的文件夹路径
        if (file != null && dir!=null && file.exists() && dir.exists()) {
            System.gc();
            boolean moveSuccess = file.renameTo(new File(dir.getPath()+File.separator+file.getName()));
            if (moveSuccess){
                parent.setDisable(true);
            }
        }
    };
    /**
     * 复制文件操作处理器
     */
    private EventHandler copyButtonHandler = event -> {
        Button button = (Button) event.getSource();
        Parent parent = button.getParent();
        File file = (File) parent.getUserData();
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择目录");
        File dir = directoryChooser.showDialog(App.getStage());
        //选择的文件夹路径
        if (file != null && dir!=null && file.exists() && dir.exists()) {
            button.setDisable(true);
            try{
                FileInputStream fis = new FileInputStream(file);//创建输入流对象
                FileOutputStream fos = new FileOutputStream(dir.getPath()+File.separator+file.getName()); //创建输出流对象
                byte[] datas = new byte[1024*8];//创建搬运工具
                int len = 0;//创建长度
                while((len = fis.read(datas))!=-1)//循环读取数据
                {
                    fos.write(datas,0,len);
                }
                fis.close();//释放资源
                fos.close();//释放资源
            }catch (Exception e){
                e.printStackTrace();
            }
            button.setDisable(false);
        }
    };


}
